(function (fruit) {
    /**
     * @class fruit.ObservableObject
     */
    fruit.define('fruit.ObservableObject', {
        events: ['propertyChanged'],
        methods: {
            init: function (inData) {
                this._data = inData || {};
            },
            get: function (inName) {
                if (this[inName]) {
                    return this[inName]();
                } else {
                    return this._data[inName];
                }
            },
            set: function (inName, inValue) {
                var oldValue = this.get(inName);
                if (oldValue !== inValue) {
                    if (this[inName]) {
                        this[inName](inValue);
                    }
                    else {
                        this._data[inName] = inValue;
                    }
                    this.notifyPropertyChanged(inName);
                }
            },
            /**
             * Trigger a "propertyChanged" event.
             * @param name
             * @param newValue
             * @param oldValue
             */
            notifyPropertyChanged: function (name, newValue, oldValue) {
                this.fire('propertyChanged', {
                    property: name,
                    oldValue: oldValue !== undefined ? oldValue : undefined,
                    newValue: newValue !== undefined ? newValue : this.get(name)
                });
            },
            /**
             * Listen to the change of certain property.
             * @param name
             * @param handler
             * @param context
             */
            listen: function (name, handler, context) {
                var property = this[name];
                if (property) {
                    property.addListener(this, handler, context);
                }
            }
        }
    });

})(fruit);
